<script setup lang="ts">
import * as monaco from "monaco-editor";
import { WarningFilled } from "@element-plus/icons-vue";
import { useGeneralDataStore, useSettingStore } from "@/store";
import { useClipboard, useThrottleFn } from "@vueuse/core";

// 导入Monaco工作器（解决加载问题）
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker";
import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker";
import jsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";

const generalDataStore = useGeneralDataStore();
const settingStore = useSettingStore();
const { copy } = useClipboard();
const copied = ref(false);
// 配置Monaco工作器
self.MonacoEnvironment = {
  getWorker(_: string, label: string) {
    if (label === "html") return new htmlWorker();
    if (label === "css" || label === "scss") return new cssWorker();
    if (label === "javascript" || label === "typescript") return new jsWorker();
    if (label === "json") return new jsonWorker();
    return new editorWorker();
  },
};

// -------------------------- 状态管理 --------------------------
// 编辑器引用与实例
const editorRef = ref<HTMLDivElement | null>(null);
const previewRef = ref<HTMLIFrameElement | null>(null);
let editorInstance: monaco.editor.IStandaloneCodeEditor | null = null;

// 核心状态
// true:显示代码区，false:显示预览区
const showEditor = ref(false);
// 错误提示
const errorMessage = ref("");
// 代码执行耗时
const executionTime = ref<number | null>(null);
// 控制Element Plus整体主题（同步编辑器深色模式）
const isDarkTheme = ref(false);
// 初始宽度
const containerWidth = ref(1000);
// 最小宽度
const minWidth = 600;
// 最大宽度
const maxWidth = 1400;
const isResizing = ref(false);
let startX = 0;
let startWidth = 0;

const startResizing = (e: MouseEvent) => {
  // 初始鼠标位置
  startX = e.clientX;
  // 初始宽度
  startWidth = containerWidth.value;
  isResizing.value = true;

  const handleMouseMove = (moveEvent: MouseEvent) => {
    if (!isResizing.value) return;

    // 注意这里取反
    const deltaX = startX - moveEvent.clientX;

    // 新宽度 = 初始宽度 + (往左移动时增加)
    let newWidth = startWidth + deltaX;

    // 限制范围
    if (newWidth < minWidth) newWidth = minWidth;
    if (newWidth > maxWidth) newWidth = maxWidth;

    containerWidth.value = newWidth;
  };

  const handleMouseUp = () => {
    isResizing.value = false;
    document.removeEventListener("mousemove", handleMouseMove);
    document.removeEventListener("mouseup", handleMouseUp);
  };

  document.addEventListener("mousemove", handleMouseMove);
  document.addEventListener("mouseup", handleMouseUp);
};

// -------------------------- 核心方法 --------------------------
// 创建/更新Monaco编辑器
const createEditor = () => {
  if (!editorRef.value) return;

  // 销毁现有编辑器（避免多实例冲突）
  if (editorInstance) editorInstance.dispose();

  // 创建编辑器（默认浅色主题）
  editorInstance = monaco.editor.create(editorRef.value, {
    value: generalDataStore.codeInfoConfig.code,
    language: generalDataStore.codeInfoConfig.language,
    theme: "vs",
    // 隐藏小地图（更简洁）
    minimap: { enabled: false },
    fontSize: 14,
    tabSize: 2,
    // 自动适应容器大小
    automaticLayout: true,
    scrollBeyondLastLine: false,
    lineNumbers: "on",
    folding: true,
    // 编辑器样式优化
    scrollbar: {
      vertical: "visible",
      horizontal: "visible",
      verticalScrollbarSize: 6,
      horizontalScrollbarSize: 6,
    },
    // 代码提示优化
    suggest: {
      showIcons: true,
    },
  });

  // 监听代码变化（实时更新代码内容）
  editorInstance.onDidChangeModelContent(() => {
    const newCode = editorInstance?.getValue() || "";
    // 避免与外部更新产生循环
    if (newCode !== generalDataStore.codeInfoConfig.code) {
      generalDataStore.codeInfoConfig.code = newCode;
      errorMessage.value = "";
    }
  });
};

// 同步编辑器内容和语言
const syncEditorContent = () => {
  if (!editorInstance) return;

  // 同步代码内容
  const currentValue = editorInstance.getValue();
  if (currentValue !== generalDataStore.codeInfoConfig.code) {
    editorInstance.setValue(generalDataStore.codeInfoConfig.code);
  }

  // 同步语言
  const model = editorInstance.getModel();
  if (model) {
    const currentLanguage = monaco.languages
      .getLanguages()
      .find((lang) => lang.id === model.getLanguageId())?.id;

    if (currentLanguage !== generalDataStore.codeInfoConfig.language) {
      monaco.editor.setModelLanguage(
        model,
        generalDataStore.codeInfoConfig.language || "text"
      );
    }
  }
};

// 切换「代码/预览」显示状态
const handleViewSwitch = () => {
  if (!showEditor.value) executeCode();
};

// 执行代码并更新预览
const executeCode = () => {
  if (!previewRef.value) return;

  errorMessage.value = "";
  const startTime = performance.now();

  try {
    const iframe = previewRef.value;
    const doc = iframe.contentDocument || iframe.contentWindow?.document;

    if (!doc) throw new Error("预览窗口加载失败，请重试");

    let htmlContent = generalDataStore.codeInfoConfig.code;
    // 处理脚本重复声明问题
    htmlContent = htmlContent.replace(
      /<script\b[^>]*>([\s\S]*?)<\/script>/gi,
      (_match, scriptContent) => {
        return `<script>
          (function() {
            ${scriptContent}
          })();
        <\/script>`;
      }
    );
    // 创建 Blob URL
    const blob = new Blob([htmlContent], { type: "text/html" });
    const url = URL.createObjectURL(blob);

    // 设置 iframe src
    iframe.src = url;

    // 清理旧的 Blob URL
    iframe.onload = () => {
      URL.revokeObjectURL(url);
      executionTime.value = Math.round(performance.now() - startTime);
    };
  } catch (err) {
    // 错误提示
    const errMsg =
      err instanceof Error ? err.message : "代码执行出错，请检查语法";
    errorMessage.value = errMsg;
    ElMessage({
      type: "error",
      message: errMsg,
      duration: 5000,
    });
    executionTime.value = null;
  }
};
// 监听代码信息变化，同步到编辑器
watch(
  () => [
    generalDataStore.codeInfoConfig.code,
    generalDataStore.codeInfoConfig.language,
  ],
  () => {
    // 确保编辑器实例已创建
    if (editorInstance) {
      syncEditorContent();
      // 如果是预览状态，自动更新预览
      if (!showEditor.value) {
        executeCode();
      }
    }
  },
  { immediate: false }
);

// 监听编辑器显示状态，初始化编辑器
watch(
  () => generalDataStore.showCodeEditor,
  (isShow) => {
    if (isShow && editorRef.value && !editorInstance) {
      nextTick(createEditor);
    }
  }
);
// -------------------------- 生命周期 --------------------------
// 组件挂载：初始化编辑器和预览
onMounted(() => {
  nextTick(() => {
    createEditor();
    // 初始加载时执行一次代码
    executeCode();
  });
});

// 组件卸载：清理编辑器实例
onUnmounted(() => {
  if (editorInstance) {
    editorInstance.dispose();
    editorInstance = null;
  }
});
// 语言和扩展名映射
const langExtMap: Record<string, string> = reactive({
  javascript: "js",
  typescript: "ts",
  vue: "vue",
  html: "html",
  css: "css",
  json: "json",
  java: "java",
  python: "py",
  c: "c",
  cpp: "cpp",
  csharp: "cs",
  go: "go",
  php: "php",
  sh: "sh",
  text: "text",
  txt: "txt",
});
// 复制功能
const copyCode = async () => {
  try {
    await copy(generalDataStore.codeInfoConfig.code);
    copied.value = true;
    setTimeout(() => (copied.value = false), 2000);
  } catch (err) {
    console.error("复制失败:", err);
  }
};
// 下载功能
const copyDownload = useThrottleFn(() => {
  const ext =
    langExtMap[generalDataStore.codeInfoConfig.language || "text"] || "txt";
  const filename = `deepseek_${ext}_${Date.now()}.${ext}`;

  const blob = new Blob([generalDataStore.codeInfoConfig.code], {
    type: "text/plain;charset=utf-8",
  });
  const url = URL.createObjectURL(blob);

  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  a.click();

  URL.revokeObjectURL(url);
}, 2000);
// 代码运行
const copyRun = () => {
  console.log("代码运行");
  ElMessage.warning("开发中...");
};
// 关闭代码编辑器
const closeCodeEditor = () => {
  settingStore.setPhoneCollapse(false);
  settingStore.setSmallCollapse(false);
  generalDataStore.showCodeEditor = false;
};
// 按钮配置
const funcBtnConfig = computed(() => {
  return [
    {
      isShow:
        generalDataStore.codeInfoConfig.language === "html" ? false : true,
      clickFunc: copyRun,
      iconConfig: {
        name: "run",
        height: "16px",
        width: "16px",
      },
      btnConfig: {
        backgroundColor: "#fff",
        hoverColor: "rgb(0 0 0 / 4%)",
        btnText: "运行",
      },
    },
    {
      isShow: true,
      clickFunc: copyCode,
      iconConfig: {
        name: copied.value ? "success" : "copy",
        height: "16px",
        width: "16px",
      },
      btnConfig: {
        backgroundColor: "#fff",
        hoverColor: "rgb(0 0 0 / 4%)",
        btnText: copied.value ? "已复制" : "复制",
      },
    },
    {
      isShow: true,
      clickFunc: copyDownload,
      iconConfig: {
        name: "download",
        height: "16px",
        width: "16px",
      },
      btnConfig: {
        backgroundColor: "#fff",
        hoverColor: "rgb(0 0 0 / 4%)",
        btnText: "下载",
      },
    },
    {
      isShow: true,
      clickFunc: closeCodeEditor,
      iconConfig: {
        name: "close",
        height: "12px",
        width: "12px",
      },
      btnConfig: {
        backgroundColor: "#fff",
        hoverColor: "",
        btnText: "",
      },
    },
  ];
});
const isHtml = computed(
  () => generalDataStore.codeInfoConfig.language === "html"
);
</script>

<template>
  <div class="sandbox-wrapper">
    <!-- 拖动条 -->
    <div class="resizer" @mousedown="startResizing"></div>
    <el-container
      class="code-sandbox-container"
      :style="{ width: containerWidth + 'px' }"
      :theme="isDarkTheme ? 'dark' : ''"
    >
      <!-- 顶部导航栏 -->
      <el-header class="sandbox-header">
        <div class="header-left">
          <el-icon class="logo-icon">
            <SvgIcon
              :name="`code-${
                langExtMap[generalDataStore.codeInfoConfig.language]
              }`"
              height="16px"
              width="16px"
            />
          </el-icon>
          <h2 class="sandbox-title">
            index.{{ langExtMap[generalDataStore.codeInfoConfig.language] }}
          </h2>
        </div>
        <div class="header-center">
          <!-- 代码/预览切换开关 -->
          <el-switch
            v-show="isHtml"
            v-model="showEditor"
            active-text="代码"
            inactive-text="预览"
            @change="handleViewSwitch"
          />
        </div>
        <div class="header-right">
          <CusTipBtn
            v-for="(item, index) in funcBtnConfig"
            v-show="item.isShow"
            :key="index"
            :isTooltip="false"
            :clickFun="item.clickFunc"
            :iconConfig="item.iconConfig"
            :btnConfig="item.btnConfig"
          />
        </div>
      </el-header>
      <!-- 主内容区（代码/预览切换显示） -->
      <el-main class="sandbox-main">
        <!-- 代码编辑区 -->
        <div v-show="showEditor || !isHtml" class="editor-wrapper">
          <!-- Monaco编辑器容器 -->
          <div ref="editorRef" class="monaco-editor-container"></div>

          <!-- 错误提示（用Element Plus消息提示替代面板） -->
          <el-message
            v-if="errorMessage"
            type="error"
            class="error-message"
            :closable="true"
          >
            <el-icon slot="icon"><WarningFilled /></el-icon>
            {{ errorMessage }}
          </el-message>
        </div>

        <!-- 预览区 -->
        <div v-show="isHtml && !showEditor" class="preview-wrapper">
          <!-- 预览iframe -->
          <div class="preview-content">
            <iframe
              ref="previewRef"
              src="about:blank"
              sandbox="allow-scripts allow-popups allow-forms allow-same-origin allow-modals"
              title="代码预览"
              class="preview-iframe"
            ></iframe>
          </div>
        </div>
      </el-main>
    </el-container>
  </div>
</template>

<style scoped lang="scss">
// 基础变量（与Element Plus风格对齐）
$primary-color: #165dff;
$light-bg: #f5f7fa;
$dark-bg: #1d2129;
$light-text: #303133;
$dark-text: #e5e6eb;
$border-light: #e4e7ed;
$border-dark: #303643;
$card-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);

.sandbox-wrapper {
  display: flex;
  height: 100vh;
  // 拖动条样式
  .resizer {
    width: 3px;
    cursor: ew-resize;
    background: #ddd;
    user-select: none;
    &:hover {
      background: #aaa;
    }
  }

  // 容器样式
  .code-sandbox-container {
    height: 100vh;
    width: 100%;
    overflow: hidden;
    // 深色主题适配
    &[theme="dark"] {
      background-color: $dark-bg;
      color: $dark-text;
    }
  }

  // 顶部导航栏
  .sandbox-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 24px;
    background-color: #fff;
    height: 56px;
    // 深色主题
    .code-sandbox-container[theme="dark"] & {
      background-color: $dark-bg;
      border-bottom-color: $border-dark;
    }
    .header-left {
      display: flex;
      align-items: center;
      gap: 5px;
      .logo-icon {
        color: $primary-color;
        font-size: 20px;
      }
      .sandbox-title {
        font-size: 18px;
        font-weight: 600;
        color: $light-text;
        margin: 0;
        .code-sandbox-container[theme="dark"] & {
          color: $dark-text;
        }
      }
    }
    .header-center {
    }
    .header-right {
    }
  }
  // 主内容区
  .sandbox-main {
    padding: 0;
    overflow: hidden;
    background-color: $light-bg;
    .code-sandbox-container[theme="dark"] & {
      background-color: $dark-bg;
    }
  }

  // 代码编辑区
  .editor-wrapper {
    height: 100%;
    display: flex;
    flex-direction: column;
    gap: 12px;
    .editor-tabs {
      --el-tabs-card-border-color: $border-light;
      --el-tabs-active-color: $primary-color;
      .code-sandbox-container[theme="dark"] & {
        --el-tabs-card-border-color: $border-dark;
        --el-tabs-active-color: $primary-color;
      }
    }
    .monaco-editor-container {
      flex: 1;
      border: 1px solid $border-light;
      overflow: hidden;
      .code-sandbox-container[theme="dark"] & {
        border-color: $border-dark;
      }
    }
    .error-message {
      margin-top: 8px;
    }
  }

  // 预览区
  .preview-wrapper {
    height: 100%;
    display: flex;
    flex-direction: column;
    gap: 16px;
    .preview-content {
      flex: 1;
      border: 1px solid $border-light;
      overflow: hidden;
      background-color: #fff;
      .code-sandbox-container[theme="dark"] & {
        border-color: $border-dark;
        background-color: $dark-bg;
      }
    }
    .preview-iframe {
      width: 100%;
      height: 100%;
      border: none;
    }
  }
}
// 响应式适配（小屏幕）
@media (max-width: 768px) {
  .sandbox-header {
    padding: 0 12px;
    .header-left .sandbox-title {
      font-size: 16px;
    }
    .header-right {
      gap: 8px;
    }
  }
  .sandbox-main {
    padding: 8px;
  }
}
</style>
